Skip to content

feat(verifier): infra-free verdict-quality measurement substrate#45

Merged
pureliture merged 2 commits into
mainfrom
claude/verifier-quality
Jun 19, 2026
Merged

feat(verifier): infra-free verdict-quality measurement substrate#45
pureliture merged 2 commits into
mainfrom
claude/verifier-quality

Conversation

@pureliture

Copy link
Copy Markdown
Contributor

Outcome

verifier-algorithm-enhancement-HANDOFF.md를 grill-to-spec(자문자답) → agentic-execution으로 수행한 결과. live Ollama 인프라 없이 verifier verdict 품질을 측정·개선·회귀방지하는 결정론적 substrate를 세운다. HANDOFF가 "이 세션의 진짜 첫 작업"으로 지목한 측정 하네스 부재(§5 MISSING #1~#7)를 해소한다.

무엇을

  • 하네스 core/evaluation/verifier_harness.pyHeuristicVerifierStrategy(path-role 앵커, 결정론적) / RecordedVerifierStrategy(기록 응답 재생) + run_corpus_delta. 기존 metrics.py를 재사용(새 메트릭 엔진 없음).
  • corpus core/evaluation/verifier_corpus.py — 단일 SoT CORPUS_CASES(22건=8 TP+14 FP, 6 path-role 전부). 생성기가 eval/verifier-corpus/harness/{candidates.jsonl,expected.json,recorded-ideal.json} 산출, freshness 테스트가 stale 차단.
  • 앵커 설정화 prompt.py DEFAULT_PATH_ROLE_ANCHORS 추출 + path_role_decision(role, anchors); yaml verification.path_role_anchorsverify_artifact.py에서 검증·partial-merge 배선. default 미설정 시 프롬프트 byte-identical(I3 보존).
  • 테스트 자동 정확도 게이트(FR3) / path-role 파라메트라이즈(FR4) / min_confidence sweep(FR6).

측정 결과 (infra-free)

  • heuristic baseline: before precision 0.3636 → after 0.5714, FP reduction 8, recall 1.0 보존(FN 0).
  • recorded ideal: after precision 1.0, FP reduction 14, strict gate(precision≥0.90/recall≥0.99) PASS.
  • min_confidence sweep: recall 전 구간 보존, 플래토 ≤0.80 / 0.80 위 절벽 → 0.60 유지 확정(숫자 근거).

불변식

I1 DEFAULT-OFF · I2 fail-closed · I3 redacted-only · I5 NEEDS_REVIEW no-write · I6 public-safe — 전부 보존. 앵커/corpus/recorded 산출물에 raw secret 없음(candidates.jsonl은 salted-sha256: 해시만).

검증

  • uv run pytest 746 passed (신규 게이트 포함, ci/pytest가 강제).
  • governance.public_safety(변경 경로) exit 0; render --validate/--check, validate_ledger 모두 exit 0.
  • 신규 파일 ruff clean.

셀프 멀티에이전트 리뷰

12 에이전트 / 5 차원(invariants·correctness·spec-compliance·test-quality·public-safety), 적대적 검증 포함. confirmed 1 nit(sweep monotonicity 단언이 평탄 수열에도 통과) → 이미 수정(reductions[0] > reductions[-1]). spec-compliance 재확인: FR1~FR8 전부 MET, hidden defer 없음, GO.

남은 것 (코드 defer 아님)

실제 Ollama end-to-end 정확도 측정 = Tailscale Ubuntu 박스 복귀 시 eval/verifier-corpus/README.md의 single command 1회 → recorded-ideal.json 자리에 실모델 출력 drop-in.

🤖 Generated with Claude Code

검증 알고리즘 고도화: live Ollama 없이 verdict 품질을 측정/회귀방지하는 결정론적 substrate.

- core/evaluation/verifier_harness.py: Heuristic/Recorded 전략 + run_corpus_delta (metrics.py 재사용)
- core/evaluation/verifier_corpus.py: 단일 SoT CORPUS_CASES(22건, 6 path-role) + 생성기
- eval/verifier-corpus/harness/: candidates.jsonl/expected.json/recorded-ideal.json (생성물, freshness 테스트로 stale 차단)
- prompt.py: path-role 앵커 추출(DEFAULT_PATH_ROLE_ANCHORS) + 설정 가능 path_role_decision
- verifier.py/client.py/verify_artifact.py: yaml verification.path_role_anchors 배선(default byte-identical, I3 보존)
- tests: 정확도 게이트(FR3)/path-role 파라메트라이즈(FR4)/min_confidence sweep(FR6)

heuristic baseline: before precision 0.3636 -> after 0.5714, FP_reduction 8, recall 1.0 보존.
min_confidence 0.60 유지(플래토 <=0.80). 전체 uv run pytest 746 green. I1~I6 불변식 보존.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces an infra-free verifier accuracy harness and a synthetic finding-level corpus to evaluate verifier quality without requiring a live model or network. It adds deterministic and recorded verifier strategies, configurable path-role anchors via YAML, and comprehensive tests for validation and threshold sweeps. The review feedback suggests optimizing redundant function calls in verifier_corpus.py, adding defensive type validation for loaded JSON in RecordedVerifierStrategy.from_file to prevent potential runtime errors, and incorporating type hints for the strategy parameter using typing.TYPE_CHECKING to enhance code maintainability.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +288 to +291
candidates = candidates or build_corpus_candidates()
by_id = {finding.finding_id: finding for finding in candidates}
responses: dict[str, dict] = {}
for case, finding in zip(CORPUS_CASES, build_corpus_candidates()):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

이 함수에서 build_corpus_candidates()가 여러 번 호출되고 있습니다. candidates가 제공되지 않았을 때 기본값으로 사용하기 위해 한 번 호출하고, 루프를 돌 때 zip에서 또 한 번 호출합니다. build_corpus_candidates()의 결과를 변수에 저장하여 재사용하면 불필요한 객체 생성과 중복 호출을 방지할 수 있습니다.

Suggested change
candidates = candidates or build_corpus_candidates()
by_id = {finding.finding_id: finding for finding in candidates}
responses: dict[str, dict] = {}
for case, finding in zip(CORPUS_CASES, build_corpus_candidates()):
default_candidates = build_corpus_candidates()
candidates = candidates or default_candidates
by_id = {finding.finding_id: finding for finding in candidates}
responses: dict[str, dict] = {}
for case, finding in zip(CORPUS_CASES, default_candidates):

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

반영했습니다 (e2f2c11) — build_corpus_candidates()를 1회만 호출하고 zip(CORPUS_CASES, candidates)로 정렬해 중복 호출을 제거했습니다. 출력은 byte-identical이라 freshness 테스트 green 유지.

Comment on lines +81 to +83
responses = data.get("responses", data) if isinstance(data, Mapping) else data
return cls(responses=responses, min_confidence=min_confidence)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

RecordedVerifierStrategy.from_file에서 로드된 JSON 데이터가 Mapping 타입인지 검증하는 로직이 미흡합니다. 만약 JSON 파일이 객체(dict)가 아닌 리스트나 다른 타입일 경우, isinstance(data, Mapping)False가 되어 responses에 그대로 할당되고, 이후 verify 메서드에서 self.responses.get 호출 시 AttributeError가 발생할 수 있습니다. 방어적 프로그래밍 관점에서 로드된 데이터와 responsesMapping 타입인지 명확히 검증하고 예외를 던지도록 개선하는 것이 좋습니다. 또한, 이러한 방어적 타입 검증을 구현할 때는 None, 숫자, 불리언, 리스트, 딕셔너리 등 다양한 예기치 않은 타입을 포함하는 포괄적인 단위 테스트를 추가하여 견고성을 보장해야 합니다.

        data = json.loads(Path(path).read_text(encoding="utf-8"))
        if not isinstance(data, Mapping):
            raise ValueError("Recorded responses file must contain a JSON object.")
        responses = data.get("responses", data)
        if not isinstance(responses, Mapping):
            raise ValueError("Recorded responses must be a mapping.")
        return cls(responses=responses, min_confidence=min_confidence)
References
  1. When implementing defensive type validation for parsed JSON fields (e.g., verifying a field is a string), ensure robustness by adding comprehensive unit tests that cover various unexpected types, including None, numbers, booleans, lists, and dictionaries.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

반영했습니다 (e2f2c11) — 로드된 JSON과 responsesMapping이 아니면 ValueError로 fail-closed 처리하고, 비-객체 타입(list/scalar/bool/null/non-mapping responses) 파라메트라이즈 테스트를 추가했습니다.

return cls(responses=responses, min_confidence=min_confidence)


def verify_candidates(candidates: list[Finding], strategy) -> list[Finding]:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

strategy 매개변수에 타입 힌트가 누락되어 있어 코드 가독성과 유지보수성이 떨어집니다. typing.TYPE_CHECKING을 활용하여 security_scanner.runtime.verify_artifact로부터 FindingVerifier 프로토콜을 가져와 타입 힌트를 추가하는 것을 권장합니다. 이렇게 하면 런타임 순환 참조(circular import) 우려 없이 정적 타입 검사를 강화할 수 있습니다.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

반영했습니다 (e2f2c11) — VerifierStrategy Protocol을 추가해 verify_candidates/run_corpus_deltastrategy에 타입 힌트를 부여했습니다.

- RecordedVerifierStrategy.from_file: fail-closed ValueError on non-mapping JSON
  (avoids later AttributeError) + parametrized type-validation test
- VerifierStrategy Protocol typing for verify_candidates/run_corpus_delta
- build_ideal_responses: single build_corpus_candidates() call (dedup)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
class VerifierStrategy(Protocol):
"""Structural type for a candidate-to-result verifier strategy."""

def verify(self, finding: Finding) -> VerifierResult: ...
@pureliture pureliture merged commit 74ae9d1 into main Jun 19, 2026
9 checks passed
@pureliture pureliture deleted the claude/verifier-quality branch June 19, 2026 23:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants